// tiny.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "tvec.h"
#include "memory.h"
#include "development.h"

#include "tileui.h"

#ifdef _DEBUG
//assert handler for tclib
void assert_msg_handler(const char* test, const char* msg, const char* file, int lineno)
{
	//limited here, no sprintf!
	OutputDebugStringA("assert failed: ");
	OutputDebugStringA(test);
	OutputDebugStringA(" - ");
	OutputDebugStringA(msg);
	OutputDebugStringA("\n");
}
#endif

class GlobalAllocator : public Allocator
{
public:
	GlobalAllocator(ID_t id) 
		: Allocator(id, 0) 
	{	}

	void* allocate(size_t sz) 
	{ 
		void* p = HeapAlloc(GetProcessHeap(), 0, sz);
		assert(p, "error: heap corruption?");
		return p;
	}
	void deallocate(void* p) { 	HeapFree(GetProcessHeap(), 0, p); }
};


//minimal windows startup and message handling
namespace Windows
{
	static TCHAR* wndClass = L"wnd";

	typedef void(*OnPaintCB)(HDC);
	static OnPaintCB paintCB = NULL;

	LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
	{
		switch(message)
		{
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		case WM_KEYDOWN:
			if(wParam == VK_ESCAPE)
				PostMessage(hWnd, WM_DESTROY, 0, 0);
			break;
		case WM_PAINT:
			if(paintCB)
			{
				HDC hdc;
				PAINTSTRUCT ps;

				hdc = BeginPaint(hWnd, &ps);
				paintCB(hdc);
				EndPaint(hWnd, &ps);
			}
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		return 0;
	}

	ATOM RegisterClass(HINSTANCE hInstance)
	{
		WNDCLASSEX wcex;
		ZeroMemory(&wcex, sizeof(WNDCLASSEX));

		wcex.cbSize = sizeof(WNDCLASSEX);
	
		wcex.style			= CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc	= Windows::WndProc;
		wcex.hInstance		= hInstance;
		wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
		wcex.lpszClassName	= wndClass;
		
		return RegisterClassEx(&wcex);
	}
}


static GlobalAllocator gGlobalAlloc(0);

#include "HTTP.h"
//#include "pugixml/pugixml.hpp"
//www.wayouthere.co.uk/feed/
#include "txml.h"


//rss data in memory
namespace RSS
{
	//doing a lot of string processing, so should perhaps have something a bit stronger.
	//none the less, this at least deals with the heap for us.
	class string
	{
	private:
		char* m_string;
		//buffer so that c_str can always return non-NULL
		static const char ms_null[6];
	public:
		string(const char* p) : m_string(NULL) 
		{ 
			if(p) 
			{ 
				size_t l = strlen(p)+1;
				m_string = static_cast<char*>(gGlobalAlloc.allocate(l)); 
				memcpy(m_string, p, l);  
			}
		}
		~string() { gGlobalAlloc.deallocate(m_string); }

		const char* c_str() const { return m_string ? m_string : ms_null; }
		size_t length() { return strlen(m_string); }
	};

	//try to guard against buggy code assuming a non-null pointer has contents!
	const char string::ms_null[6] = { '0', 'b', 'a', 'd', '!', '0' };

	class Channel
	{
		string title, link, desc;
		int newest_date;
	};

	class Item
	{
		string title, desc, link;
		int date;
	};
};

class Consumer : public TXML::Consumer
{
private:
	void print(const TXML::String& s)
	{
		//too long
		if(s.length() > 1022)
			return;

		char buffer[1024];
		memcpy(buffer, s.begin(), s.length());
		buffer[s.length()] = '\n';
		buffer[s.length()+1] = 0;
		OutputDebugStringA(buffer);
	}
	int stack;
public:
	void BeginElement(const TXML::String& name, const TXML::String& ns) 
	{
		++stack;
		print(name);
	}
	void ElementContents(const TXML::String& text) 
	{

	}
	void EndElement() 
	{
		--stack;
	}

	void BeginDocument(const TXML::String& name, const TXML::String& ns)
	{
		++stack;
		print(name);
	}
	void EndDocument()
	{
		--stack;
	}

	void Attribute(const TXML::String& name, const TXML::String& ns, const TXML::String& value) {}
	void NamespaceDeclaration(const TXML::String& ns, const TXML::String& uri){}
	void Encoding() {}

	void CData(const TXML::String& cdata) {}

	//errors:
	void ElementError(const TXML::String& elem) {}
	void AttributeError(const TXML::String& attr) {}
	void ParseError(TXML::EParseErrors error) {}

	Consumer() : stack(0) {}
};


void OnPaint(HDC hdc)
{
	TileUI::TestPaint(hdc, &gGlobalAlloc);
}

//entry point. using a windows-style entry point since it requires less processing of enter()
//than the C-style entry point (no cmd parsing => no heap alloc and less processing to get here).
extern int __stdcall wmain(HINSTANCE hInstance, LPTSTR lpCommandLine, int nCmdShow)
{
//	TileUI::StaticCreate();
	Windows::paintCB = OnPaint;

	Windows::RegisterClass(hInstance);

	RECT rc = {0,0,700,500};
	AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, false);
	HWND wnd = CreateWindow(Windows::wndClass, L"tiny", WS_OVERLAPPEDWINDOW, 10, 10, rc.right - rc.left, rc.bottom - rc.top, 0, 0, hInstance, 0);
	ShowWindow(wnd, nCmdShow);
	UpdateWindow(wnd);

	const size_t sz = 64*1024;
	char* buffer = (char*)gGlobalAlloc.allocate(sz);
	//DWORD r = INET::HTTPRequest("www.wayouthere.co.uk", "/feed/", buffer, sz);
	//http://twitter.com/statuses/user_timeline/smashed_pumpkin.atom
	//DWORD r = INET::HTTPRequest("twitter.com", "/statuses/user_timeline/majornelson.rss", buffer, sz);

	Consumer C;
	{
		Development::File data("sample.xml", &gGlobalAlloc);
		TXML::Parser P;
		P.Parse(data.mpBuffer, &C);
	}
	
	while(true)
	{
		MSG msg;
		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) //gather messages for all windows
		{
			if(msg.message == WM_QUIT)
			{
			//	TileUI::StaticDestroy();
				return msg.wParam;
			}
			else if(msg.message > WM_APP)
			{
				//todo: handle messages from worker threads
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}			
		}

	}

	return 0;
}















